Implement priority and tag selection in task creation version 1#31
Implement priority and tag selection in task creation version 1#31
Conversation
|
Caution Review failedPull request was closed or merged during review 📝 WalkthroughWalkthroughAdded priority and tag data to the task model, a TaskViewModel for state, priority/tag selector widgets, integrated selectors into task creation, and reworked the home screen to consume the view model with grouping, filtering, and sorting by priority. README shortened accordingly. Changes
Sequence DiagramsequenceDiagram
participant User
participant UI as CreateTaskScreen
participant VM as TaskViewModel
participant Model as TaskModel
User->>UI: Open create task screen
UI->>VM: context.watch<TaskViewModel>()
VM-->>UI: selectedPriority, availableTags
User->>UI: Tap priority card
UI->>VM: setPriority(priority)
VM->>VM: update selectedPriority, notifyListeners()
VM-->>UI: rebuild (new selection)
User->>UI: Tap tag pill
UI->>VM: toggleTag(tag)
VM->>VM: add/remove tag, notifyListeners()
VM-->>UI: rebuild (tag selection)
User->>UI: Fill fields and tap Create
UI->>Model: Construct TaskModel(title, desc, priority, tags, ...)
UI->>VM: addTask(newTask)
VM->>VM: append to _tasks, notifyListeners()
VM->>VM: reset() selectedPriority/tags
UI->>User: Navigator.pop(context)
Estimated Code Review Effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested Reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/lib/main.dart (1)
21-25:⚠️ Potential issue | 🔴 CriticalFail fast when Supabase config is missing.
Line 21 detects empty credentials but line 25 still initializes Supabase with them. This allows the app to start in a broken state where subsequent Supabase operations fail silently at runtime. The empty string credentials are then accessed by downstream code without validation, leading to cascading failures in auth_gate, statistics_service, and other services that depend on a properly initialized client.
Suggested fix
if (supabaseUrl.isEmpty || supabaseAnonKey.isEmpty) { - debugPrint('Error: SUPABASE_URL or SUPABASE_ANON_KEY is missing'); + throw StateError('SUPABASE_URL or SUPABASE_ANON_KEY is missing'); } await Supabase.initialize(url: supabaseUrl, anonKey: supabaseAnonKey);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/main.dart` around lines 21 - 25, The code logs missing Supabase credentials but still calls Supabase.initialize with empty strings; update the startup check in main (the supabaseUrl / supabaseAnonKey validation) to fail fast by throwing an exception or terminating startup instead of continuing—replace the debugPrint-only behavior with a thrown StateError or process exit when supabaseUrl.isEmpty || supabaseAnonKey.isEmpty so Supabase.initialize is never invoked with invalid values; keep the validation tied to the same symbols (supabaseUrl, supabaseAnonKey, Supabase.initialize) so downstream services (auth_gate, statistics_service) never run against an uninitialized client.
🧹 Nitpick comments (2)
src/lib/features/tasks/view/screens/home_screen.dart (1)
16-25: CacheviewModel.tasksbefore grouping.
viewModel.tasksrecomputes filtering/sorting every time the getter is read. The current loop does that once per priority bucket on every rebuild.Suggested refactor
- Map<Priority, List<TaskModel>> grouped = {}; - for (var priority in Priority.values.reversed) { - final tasks = viewModel.tasks + final visibleTasks = viewModel.tasks; + final Map<Priority, List<TaskModel>> grouped = {}; + for (final priority in Priority.values.reversed) { + final tasks = visibleTasks .where((t) => t.priority == priority) .toList(); if (tasks.isNotEmpty) grouped[priority] = tasks; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/features/tasks/view/screens/home_screen.dart` around lines 16 - 25, Cache the TaskViewModel.tasks result into a local variable before grouping to avoid re-evaluating the getter on each priority iteration: call the getter once (e.g., final allTasks = viewModel.tasks) and then use allTasks.where(...) inside the loop that builds grouped (using Priority.values.reversed, grouped Map, and the existing TaskModel/priority checks) so the expensive filtering/sorting is not recomputed per priority.src/lib/features/tasks/viewmodel/task_viewmodel.dart (1)
6-18: HideavailableTagsbehind an unmodifiable getter.Right now any caller can mutate the tag catalog directly and bypass
notifyListeners(). Making the list private and exposingList.unmodifiable(...)keeps the view model as the single mutation point.Suggested refactor
- final List<TagModel> availableTags = [ + final List<TagModel> _availableTags = [ TagModel(id: 'work', name: 'Work', color: const Color(0xFF2196F3)), TagModel(id: 'study', name: 'Study', color: const Color(0xFF9C27B0)), TagModel(id: 'personal', name: 'Personal', color: const Color(0xFF4CAF50)), TagModel(id: 'project', name: 'Project', color: const Color(0xFFFF9800)), ]; + + List<TagModel> get availableTags => List.unmodifiable(_availableTags);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/features/tasks/viewmodel/task_viewmodel.dart` around lines 6 - 18, Make the public mutable availableTags list private and expose it via an unmodifiable getter: rename availableTags to _availableTags (keep its initial TagModel entries), and add a getter List<TagModel> get availableTags => List.unmodifiable(_availableTags); this ensures callers cannot mutate the catalog directly (forcing mutations through the viewmodel and notifyListeners) while leaving selectedPriority, _selectedTags, and the selectedTags getter unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/lib/features/tasks/view/screens/create_task_screen.dart`:
- Around line 266-289: Before calling viewModel.addTask(...) in the onPressed
handler, validate that _endTime is after _startTime (not equal or earlier); if
the check fails, do not call viewModel.addTask or viewModel.reset, and instead
show user feedback (e.g., ScaffoldMessenger.of(context).showSnackBar or similar)
explaining the time range is invalid. Update the onPressed block in
create_task_screen.dart around the existing onPressed closure so it checks
_startTime and _endTime, returns early on invalid range, and only constructs
TaskModel and calls TaskViewModel.addTask/reset when the times are valid.
- Around line 105-121: The onSelected handler for the ChoiceChip is resetting
_selectedCategoryIndex to 0 when a selected chip is tapped (false branch) which
forces the category back to "Development"; change the handler in the ChoiceChip
that references _selectedCategoryIndex so it only updates state when selected ==
true (e.g., inside setState assign _selectedCategoryIndex = index when selected)
and ignore the false case (do not reset to 0) so deselecting does not overwrite
the previously chosen category.
- Around line 145-150: TaskViewModel is app-scoped so previous selections
persist; call TaskViewModel.reset() when the form opens (not only on successful
create). Add a reset invocation in the screen's entry point—e.g. in
CreateTaskScreen's initState() (or the equivalent hook where the widget is
created) call context.read<TaskViewModel>().reset() (or
ref.read(TaskViewModel).reset() depending on your provider API) so
PrioritySelector and TagSelector start with a clean state whenever the form is
presented.
In `@src/lib/features/tasks/view/screens/home_screen.dart`:
- Around line 149-190: Replace the raw GestureDetector + AnimatedContainer used
for the sort control with a semantic, focusable Material widget such as
FilterChip or ChoiceChip (or wrap the AnimatedContainer with InkWell inside a
Material) so it supports keyboard navigation, focus/pressed states and
accessibility semantics; specifically change the GestureDetector that calls
viewModel.toggleSortByPriority() to use a FilterChip/ChoiceChip (or InkWell in
Material) and map its selected state to viewModel.sortByPriority and its
onSelected/onChanged to viewModel.toggleSortByPriority(), and do the same
replacement for the custom _FilterChip so both controls gain proper
focusability, pressed visuals and accessibility labels instead of relying on
GestureDetector.
In `@src/lib/features/tasks/view/widgets/priority_selector.dart`:
- Around line 18-57: Replace the custom GestureDetector+AnimatedContainer
implementation with a proper selectable Material control (e.g., ChoiceChip)
inside the Priority.values.map so keyboard and screen-reader interaction are
automatic; for each priority, use ChoiceChip with selected:
viewModel.selectedPriority == priority, onSelected: (_) =>
viewModel.setPriority(priority), avatar/icon using priority.icon, label using
priority.label, and apply selectedColor: priority.color and backgroundColor:
Color(0xFFF1F7FD) plus a rounded shape/border to match the current visuals—this
keeps the Priority.values mapping, viewModel.setPriority, and
viewModel.selectedPriority references while providing built-in semantics and
keyboard support.
In `@src/lib/features/tasks/view/widgets/tag_selector.dart`:
- Around line 17-55: Replace the custom GestureDetector + AnimatedContainer tag
widgets with Flutter's FilterChip to restore proper accessibility and
focus/selection semantics: in the Wrap over viewModel.availableTags (where you
currently call viewModel.isTagSelected(tag) and viewModel.toggleTag(tag)),
render a FilterChip per tag with selected set from viewModel.isTagSelected(tag),
onSelected calling viewModel.toggleTag(tag), label using Text(tag.name) and
styling via selectedColor (tag.color), backgroundColor
(tag.color.withOpacity(0.1)), labelStyle (use white when selected, tag.color
when not), padding and shape (BorderRadius.circular(20)) to match current
visuals, and optionally provide a selectedIcon (Icons.check) to mimic the
existing check display.
---
Outside diff comments:
In `@src/lib/main.dart`:
- Around line 21-25: The code logs missing Supabase credentials but still calls
Supabase.initialize with empty strings; update the startup check in main (the
supabaseUrl / supabaseAnonKey validation) to fail fast by throwing an exception
or terminating startup instead of continuing—replace the debugPrint-only
behavior with a thrown StateError or process exit when supabaseUrl.isEmpty ||
supabaseAnonKey.isEmpty so Supabase.initialize is never invoked with invalid
values; keep the validation tied to the same symbols (supabaseUrl,
supabaseAnonKey, Supabase.initialize) so downstream services (auth_gate,
statistics_service) never run against an uninitialized client.
---
Nitpick comments:
In `@src/lib/features/tasks/view/screens/home_screen.dart`:
- Around line 16-25: Cache the TaskViewModel.tasks result into a local variable
before grouping to avoid re-evaluating the getter on each priority iteration:
call the getter once (e.g., final allTasks = viewModel.tasks) and then use
allTasks.where(...) inside the loop that builds grouped (using
Priority.values.reversed, grouped Map, and the existing TaskModel/priority
checks) so the expensive filtering/sorting is not recomputed per priority.
In `@src/lib/features/tasks/viewmodel/task_viewmodel.dart`:
- Around line 6-18: Make the public mutable availableTags list private and
expose it via an unmodifiable getter: rename availableTags to _availableTags
(keep its initial TagModel entries), and add a getter List<TagModel> get
availableTags => List.unmodifiable(_availableTags); this ensures callers cannot
mutate the catalog directly (forcing mutations through the viewmodel and
notifyListeners) while leaving selectedPriority, _selectedTags, and the
selectedTags getter unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 419ac100-97fd-4942-9166-bde14c25d86a
📒 Files selected for processing (8)
README.mdsrc/lib/features/tasks/model/task_model.dartsrc/lib/features/tasks/view/screens/create_task_screen.dartsrc/lib/features/tasks/view/screens/home_screen.dartsrc/lib/features/tasks/view/widgets/priority_selector.dartsrc/lib/features/tasks/view/widgets/tag_selector.dartsrc/lib/features/tasks/viewmodel/task_viewmodel.dartsrc/lib/main.dart
| List<String> categories = [ | ||
| 'Development', | ||
| 'Research', | ||
| 'Design', | ||
| 'Backend', | ||
| ]; | ||
| bool isSelected = index == _selectedCategoryIndex; | ||
| return Padding( | ||
| padding: const EdgeInsets.only(right: 10), | ||
| child: ChoiceChip( | ||
| label: Text(categories[index]), | ||
| selected: isSelected, | ||
| onSelected: (selected) => setState(() => _selectedCategoryIndex = selected ? index : 0), | ||
| onSelected: (selected) => setState( | ||
| () => _selectedCategoryIndex = selected | ||
| ? index | ||
| : 0, | ||
| ), |
There was a problem hiding this comment.
Don't reset the category to index 0 on deselect.
Tapping an already-selected chip currently changes the task category back to Development. For a single-select control, the false branch should usually be ignored instead of silently rewriting the value.
Suggested fix
- onSelected: (selected) => setState(
- () => _selectedCategoryIndex = selected
- ? index
- : 0,
- ),
+ onSelected: (selected) {
+ if (!selected) return;
+ setState(() => _selectedCategoryIndex = index);
+ },📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| List<String> categories = [ | |
| 'Development', | |
| 'Research', | |
| 'Design', | |
| 'Backend', | |
| ]; | |
| bool isSelected = index == _selectedCategoryIndex; | |
| return Padding( | |
| padding: const EdgeInsets.only(right: 10), | |
| child: ChoiceChip( | |
| label: Text(categories[index]), | |
| selected: isSelected, | |
| onSelected: (selected) => setState(() => _selectedCategoryIndex = selected ? index : 0), | |
| onSelected: (selected) => setState( | |
| () => _selectedCategoryIndex = selected | |
| ? index | |
| : 0, | |
| ), | |
| List<String> categories = [ | |
| 'Development', | |
| 'Research', | |
| 'Design', | |
| 'Backend', | |
| ]; | |
| bool isSelected = index == _selectedCategoryIndex; | |
| return Padding( | |
| padding: const EdgeInsets.only(right: 10), | |
| child: ChoiceChip( | |
| label: Text(categories[index]), | |
| selected: isSelected, | |
| onSelected: (selected) { | |
| if (!selected) return; | |
| setState(() => _selectedCategoryIndex = index); | |
| }, |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/lib/features/tasks/view/screens/create_task_screen.dart` around lines 105
- 121, The onSelected handler for the ChoiceChip is resetting
_selectedCategoryIndex to 0 when a selected chip is tapped (false branch) which
forces the category back to "Development"; change the handler in the ChoiceChip
that references _selectedCategoryIndex so it only updates state when selected ==
true (e.g., inside setState assign _selectedCategoryIndex = index when selected)
and ignore the false case (do not reset to 0) so deselecting does not overwrite
the previously chosen category.
| // ─── PRIORITY SELECTOR (MỚI) ────────────── | ||
| const PrioritySelector(), | ||
| const SizedBox(height: 20), | ||
|
|
||
| // ─── TAG SELECTOR (MỚI) ─────────────────── | ||
| const TagSelector(), |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's check if main.dart exists and look for TaskViewModel provision
find . -type f -name "main.dart" | head -5Repository: tqha1011/TaskManagement
Length of output: 86
🏁 Script executed:
# Search for TaskViewModel provider setup
rg -i "taskviewmodel" --type dart | head -20Repository: tqha1011/TaskManagement
Length of output: 857
🏁 Script executed:
# Check the create_task_screen.dart file structure
cat -n src/lib/features/tasks/view/screens/create_task_screen.dart | head -50Repository: tqha1011/TaskManagement
Length of output: 2234
🏁 Script executed:
# Search for reset() calls in create_task_screen.dart
rg "reset" src/lib/features/tasks/view/screens/create_task_screen.dart -nRepository: tqha1011/TaskManagement
Length of output: 115
🏁 Script executed:
# Read lines 140-160 to see context around lines 145-150
sed -n '140,160p' src/lib/features/tasks/view/screens/create_task_screen.dartRepository: tqha1011/TaskManagement
Length of output: 843
🏁 Script executed:
# Read lines 260-295 to see the "Also applies to" section
sed -n '260,295p' src/lib/features/tasks/view/screens/create_task_screen.dartRepository: tqha1011/TaskManagement
Length of output: 1820
🏁 Script executed:
# Check main.dart for the full provider setup and scope
cat -n src/lib/main.dart | grep -A 10 -B 5 "TaskViewModel"Repository: tqha1011/TaskManagement
Length of output: 702
🏁 Script executed:
# Check if there's an initState() method already in _CreateTaskScreenState
sed -n '19,100p' src/lib/features/tasks/view/screens/create_task_screen.dart | grep -A 5 "initState"Repository: tqha1011/TaskManagement
Length of output: 49
🏁 Script executed:
# Look at the full dispose/lifecycle methods
rg "dispose|initState|deactivate" src/lib/features/tasks/view/screens/create_task_screen.dart -A 3Repository: tqha1011/TaskManagement
Length of output: 49
🏁 Script executed:
# Get more context around where reset() is called - show the full button handler
sed -n '265,300p' src/lib/features/tasks/view/screens/create_task_screen.dartRepository: tqha1011/TaskManagement
Length of output: 1865
🏁 Script executed:
# Check TaskViewModel.reset() method to understand what it does
rg -A 10 "void reset" src/lib/features/tasks/viewmodel/task_viewmodel.dartRepository: tqha1011/TaskManagement
Length of output: 337
🏁 Script executed:
# Check if there's any WillPopScope or onBack handling
rg "WillPopScope|onPopInvoked|pop|Navigator" src/lib/features/tasks/view/screens/create_task_screen.dart -nRepository: tqha1011/TaskManagement
Length of output: 184
🏁 Script executed:
# Let's see the entire _CreateTaskScreenState class to understand its full structure
wc -l src/lib/features/tasks/view/screens/create_task_screen.dartRepository: tqha1011/TaskManagement
Length of output: 130
🏁 Script executed:
# Read more of the file to see if there are any other reset patterns
sed -n '1,50p' src/lib/features/tasks/view/screens/create_task_screen.dartRepository: tqha1011/TaskManagement
Length of output: 1884
🏁 Script executed:
# Check how the CreateTaskScreen is navigated to
rg "CreateTaskScreen" src/lib/features/tasks/view/screens/ -nRepository: tqha1011/TaskManagement
Length of output: 667
🏁 Script executed:
# Check the back button at line 64 - what does it do exactly?
sed -n '55,75p' src/lib/features/tasks/view/screens/create_task_screen.dartRepository: tqha1011/TaskManagement
Length of output: 926
🏁 Script executed:
# Check if PrioritySelector and TagSelector have their own state management
cat -n src/lib/features/tasks/view/widgets/priority_selector.dart | head -40Repository: tqha1011/TaskManagement
Length of output: 1959
🏁 Script executed:
# Look for any other screens or routes that might open CreateTaskScreen
rg "CreateTaskScreen\|push\|pushNamed" src/lib/features/tasks/view/screens/home_screen.dart -B 2 -A 2Repository: tqha1011/TaskManagement
Length of output: 49
Reset provider state when the form opens.
TaskViewModel is app-scoped in src/lib/main.dart. The back button (line 64) closes the form without calling reset(), so previously selected priority/tags persist when the form reopens. Only the successful create path (line 287) calls reset().
Suggested fix
class _CreateTaskScreenState extends State<CreateTaskScreen> {
+ `@override`
+ void initState() {
+ super.initState();
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ if (mounted) context.read<TaskViewModel>().reset();
+ });
+ }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/lib/features/tasks/view/screens/create_task_screen.dart` around lines 145
- 150, TaskViewModel is app-scoped so previous selections persist; call
TaskViewModel.reset() when the form opens (not only on successful create). Add a
reset invocation in the screen's entry point—e.g. in CreateTaskScreen's
initState() (or the equivalent hook where the widget is created) call
context.read<TaskViewModel>().reset() (or ref.read(TaskViewModel).reset()
depending on your provider API) so PrioritySelector and TagSelector start with a
clean state whenever the form is presented.
| onPressed: () { | ||
| final viewModel = context.read<TaskViewModel>(); | ||
| final List<String> categories = [ | ||
| 'Development', | ||
| 'Research', | ||
| 'Design', | ||
| 'Backend', | ||
| ]; | ||
| final newTask = TaskModel( | ||
| id: DateTime.now().millisecondsSinceEpoch | ||
| .toString(), | ||
| title: _nameController.text, | ||
| description: _descController.text, | ||
| category: categories[_selectedCategoryIndex], | ||
| startTime: _startTime, | ||
| endTime: _endTime, | ||
| date: _selectedDate, | ||
| priority: viewModel.selectedPriority, | ||
| tags: List.from(viewModel.selectedTags), | ||
| ); | ||
| viewModel.addTask(newTask); | ||
| viewModel.reset(); | ||
| Navigator.pop(context); | ||
| }, |
There was a problem hiding this comment.
Validate the time range before creating the task.
Nothing prevents endTime from being earlier than or equal to startTime, so this can save impossible tasks. Guard it before addTask(...) and show feedback instead of creating the item.
Suggested fix
onPressed: () {
final viewModel = context.read<TaskViewModel>();
+ final startMinutes =
+ _startTime.hour * 60 + _startTime.minute;
+ final endMinutes =
+ _endTime.hour * 60 + _endTime.minute;
+ if (endMinutes <= startMinutes) {
+ ScaffoldMessenger.of(context).showSnackBar(
+ const SnackBar(
+ content: Text('End time must be after start time'),
+ ),
+ );
+ return;
+ }
final List<String> categories = [
'Development',
'Research',
'Design',
'Backend',📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| onPressed: () { | |
| final viewModel = context.read<TaskViewModel>(); | |
| final List<String> categories = [ | |
| 'Development', | |
| 'Research', | |
| 'Design', | |
| 'Backend', | |
| ]; | |
| final newTask = TaskModel( | |
| id: DateTime.now().millisecondsSinceEpoch | |
| .toString(), | |
| title: _nameController.text, | |
| description: _descController.text, | |
| category: categories[_selectedCategoryIndex], | |
| startTime: _startTime, | |
| endTime: _endTime, | |
| date: _selectedDate, | |
| priority: viewModel.selectedPriority, | |
| tags: List.from(viewModel.selectedTags), | |
| ); | |
| viewModel.addTask(newTask); | |
| viewModel.reset(); | |
| Navigator.pop(context); | |
| }, | |
| onPressed: () { | |
| final viewModel = context.read<TaskViewModel>(); | |
| final startMinutes = | |
| _startTime.hour * 60 + _startTime.minute; | |
| final endMinutes = | |
| _endTime.hour * 60 + _endTime.minute; | |
| if (endMinutes <= startMinutes) { | |
| ScaffoldMessenger.of(context).showSnackBar( | |
| const SnackBar( | |
| content: Text('End time must be after start time'), | |
| ), | |
| ); | |
| return; | |
| } | |
| final List<String> categories = [ | |
| 'Development', | |
| 'Research', | |
| 'Design', | |
| 'Backend', | |
| ]; | |
| final newTask = TaskModel( | |
| id: DateTime.now().millisecondsSinceEpoch | |
| .toString(), | |
| title: _nameController.text, | |
| description: _descController.text, | |
| category: categories[_selectedCategoryIndex], | |
| startTime: _startTime, | |
| endTime: _endTime, | |
| date: _selectedDate, | |
| priority: viewModel.selectedPriority, | |
| tags: List.from(viewModel.selectedTags), | |
| ); | |
| viewModel.addTask(newTask); | |
| viewModel.reset(); | |
| Navigator.pop(context); | |
| }, |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/lib/features/tasks/view/screens/create_task_screen.dart` around lines 266
- 289, Before calling viewModel.addTask(...) in the onPressed handler, validate
that _endTime is after _startTime (not equal or earlier); if the check fails, do
not call viewModel.addTask or viewModel.reset, and instead show user feedback
(e.g., ScaffoldMessenger.of(context).showSnackBar or similar) explaining the
time range is invalid. Update the onPressed block in create_task_screen.dart
around the existing onPressed closure so it checks _startTime and _endTime,
returns early on invalid range, and only constructs TaskModel and calls
TaskViewModel.addTask/reset when the times are valid.
| GestureDetector( | ||
| onTap: () => viewModel.toggleSortByPriority(), | ||
| child: AnimatedContainer( | ||
| duration: const Duration(milliseconds: 200), | ||
| padding: const EdgeInsets.symmetric( | ||
| horizontal: 12, | ||
| vertical: 7, | ||
| ), | ||
| decoration: BoxDecoration( | ||
| color: viewModel.sortByPriority | ||
| ? AppColors.primaryBlue | ||
| : Colors.white, | ||
| borderRadius: BorderRadius.circular(20), | ||
| border: Border.all( | ||
| color: AppColors.primaryBlue, | ||
| width: 1, | ||
| ), | ||
| ), | ||
| child: Row( | ||
| children: [ | ||
| Icon( | ||
| Icons.sort, | ||
| size: 16, | ||
| color: viewModel.sortByPriority | ||
| ? Colors.white | ||
| : AppColors.primaryBlue, | ||
| ), | ||
| ) | ||
| ], | ||
| const SizedBox(width: 5), | ||
| Text( | ||
| 'Sort', | ||
| style: TextStyle( | ||
| fontSize: 12, | ||
| fontWeight: FontWeight.w600, | ||
| color: viewModel.sortByPriority | ||
| ? Colors.white | ||
| : AppColors.primaryBlue, | ||
| ), | ||
| ), | ||
| ], | ||
| ), | ||
| ), | ||
| ), |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# First, let's check if the file exists and its size
wc -l src/lib/features/tasks/view/screens/home_screen.dartRepository: tqha1011/TaskManagement
Length of output: 123
🏁 Script executed:
#!/bin/bash
# Read lines 149-190 to see the sort button implementation
sed -n '149,190p' src/lib/features/tasks/view/screens/home_screen.dartRepository: tqha1011/TaskManagement
Length of output: 2032
🏁 Script executed:
#!/bin/bash
# Read lines 356-390 to see the _FilterChip implementation
sed -n '356,390p' src/lib/features/tasks/view/screens/home_screen.dartRepository: tqha1011/TaskManagement
Length of output: 1029
🏁 Script executed:
#!/bin/bash
# Search for _FilterChip definition to understand its implementation
rg -A 20 'class _FilterChip|_FilterChip\(' src/lib/features/tasks/view/screens/home_screen.dartRepository: tqha1011/TaskManagement
Length of output: 2294
🏁 Script executed:
#!/bin/bash
# Look at wider context around line 149 (from 140-200) to see parent widgets
sed -n '140,200p' src/lib/features/tasks/view/screens/home_screen.dartRepository: tqha1011/TaskManagement
Length of output: 2763
🏁 Script executed:
#!/bin/bash
# Search for Material widgets in the file
rg -n 'Material\(' src/lib/features/tasks/view/screens/home_screen.dartRepository: tqha1011/TaskManagement
Length of output: 49
🏁 Script executed:
#!/antml/bin
# Search for Semantics usage in the file
rg -n 'Semantics' src/lib/features/tasks/view/screens/home_screen.dartRepository: tqha1011/TaskManagement
Length of output: 49
🏁 Script executed:
#!/bin/bash
# Search for GestureDetector to see all usages and their context
rg -B 2 -A 2 'GestureDetector' src/lib/features/tasks/view/screens/home_screen.dart | head -60Repository: tqha1011/TaskManagement
Length of output: 429
🏁 Script executed:
#!/bin/bash
# Check if Material or Scaffold widget wraps the entire screen
sed -n '1,100p' src/lib/features/tasks/view/screens/home_screen.dart | grep -n -A 5 'build\|Scaffold\|Material'Repository: tqha1011/TaskManagement
Length of output: 772
🏁 Script executed:
#!/bin/bash
# Look for any MaterialApp or Material widget context in the file
rg -n 'Scaffold|MaterialApp|Material' src/lib/features/tasks/view/screens/home_screen.dart | head -20Repository: tqha1011/TaskManagement
Length of output: 142
🏁 Script executed:
#!/bin/bash
# Let's check the full structure around the build method to see the widget tree
sed -n '14,30p' src/lib/features/tasks/view/screens/home_screen.dartRepository: tqha1011/TaskManagement
Length of output: 620
🏁 Script executed:
#!/bin/bash
# Check if there are any other interactive widgets in the file to compare patterns
rg -n 'InkWell|FilterChip|ChoiceChip' src/lib/features/tasks/view/screens/home_screen.dartRepository: tqha1011/TaskManagement
Length of output: 245
Sort and filter controls need focusable/semantic widgets.
Both the sort button and _FilterChip are wired through GestureDetector, missing keyboard navigation, pressed states, and selected semantics. These are primary navigation controls on the screen—use FilterChip/ChoiceChip/InkWell inside Material instead.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/lib/features/tasks/view/screens/home_screen.dart` around lines 149 - 190,
Replace the raw GestureDetector + AnimatedContainer used for the sort control
with a semantic, focusable Material widget such as FilterChip or ChoiceChip (or
wrap the AnimatedContainer with InkWell inside a Material) so it supports
keyboard navigation, focus/pressed states and accessibility semantics;
specifically change the GestureDetector that calls
viewModel.toggleSortByPriority() to use a FilterChip/ChoiceChip (or InkWell in
Material) and map its selected state to viewModel.sortByPriority and its
onSelected/onChanged to viewModel.toggleSortByPriority(), and do the same
replacement for the custom _FilterChip so both controls gain proper
focusability, pressed visuals and accessibility labels instead of relying on
GestureDetector.
| Row( | ||
| children: Priority.values.map((priority) { | ||
| final isSelected = viewModel.selectedPriority == priority; | ||
| return Expanded( | ||
| child: Padding( | ||
| padding: const EdgeInsets.only(right: 8), | ||
| child: GestureDetector( | ||
| onTap: () => viewModel.setPriority(priority), | ||
| child: AnimatedContainer( | ||
| duration: const Duration(milliseconds: 200), | ||
| padding: const EdgeInsets.symmetric(vertical: 10), | ||
| decoration: BoxDecoration( | ||
| color: isSelected | ||
| ? priority.color | ||
| : const Color(0xFFF1F7FD), | ||
| borderRadius: BorderRadius.circular(12), | ||
| border: Border.all( | ||
| color: isSelected ? priority.color : Colors.transparent, | ||
| ), | ||
| ), | ||
| child: Column( | ||
| children: [ | ||
| Icon( | ||
| priority.icon, | ||
| color: isSelected ? Colors.white : priority.color, | ||
| size: 20, | ||
| ), | ||
| const SizedBox(height: 4), | ||
| Text( | ||
| priority.label, | ||
| style: TextStyle( | ||
| fontSize: 11, | ||
| fontWeight: FontWeight.w600, | ||
| color: isSelected ? Colors.white : priority.color, | ||
| ), | ||
| ), | ||
| ], | ||
| ), | ||
| ), | ||
| ), |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n src/lib/features/tasks/view/widgets/priority_selector.dartRepository: tqha1011/TaskManagement
Length of output: 2892
🏁 Script executed:
rg -n "class Priority|enum Priority" src/lib/features/tasks/model/task_model.dart -A 20Repository: tqha1011/TaskManagement
Length of output: 608
🏁 Script executed:
rg -n "Semantics|GestureDetector|InkWell" src/lib/features/tasks/view/widgets/priority_selector.dartRepository: tqha1011/TaskManagement
Length of output: 109
🏁 Script executed:
rg -n "FocusNode|onKey|RawKeyboardListener|Focus\(" src/lib/features/tasks/view/widgets/priority_selector.dartRepository: tqha1011/TaskManagement
Length of output: 49
🏁 Script executed:
rg -n "ChoiceChip|Radio\(" src/lib/features/tasks/view/widgets/ -t dartRepository: tqha1011/TaskManagement
Length of output: 49
🏁 Script executed:
fd "priority_selector" src/lib/features/tasks/view/widgets/ -t fRepository: tqha1011/TaskManagement
Length of output: 125
🏁 Script executed:
rg -n "Semantics|SemanticButton|selectableButton" src/lib/features/tasks/view/widgets/ -t dartRepository: tqha1011/TaskManagement
Length of output: 49
Use an accessible selection control for priorities.
The priority options are implemented with GestureDetector without any semantics wrapper or keyboard support, making them inaccessible to screen readers and keyboard users. Replace with a proper selectable control such as ChoiceChip or Radio buttons, which provide keyboard navigation, semantic information, and Material interaction feedback automatically.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/lib/features/tasks/view/widgets/priority_selector.dart` around lines 18 -
57, Replace the custom GestureDetector+AnimatedContainer implementation with a
proper selectable Material control (e.g., ChoiceChip) inside the
Priority.values.map so keyboard and screen-reader interaction are automatic; for
each priority, use ChoiceChip with selected: viewModel.selectedPriority ==
priority, onSelected: (_) => viewModel.setPriority(priority), avatar/icon using
priority.icon, label using priority.label, and apply selectedColor:
priority.color and backgroundColor: Color(0xFFF1F7FD) plus a rounded
shape/border to match the current visuals—this keeps the Priority.values
mapping, viewModel.setPriority, and viewModel.selectedPriority references while
providing built-in semantics and keyboard support.
| Wrap( | ||
| spacing: 8, | ||
| runSpacing: 8, | ||
| children: viewModel.availableTags.map((tag) { | ||
| final isSelected = viewModel.isTagSelected(tag); | ||
| return GestureDetector( | ||
| onTap: () => viewModel.toggleTag(tag), | ||
| child: AnimatedContainer( | ||
| duration: const Duration(milliseconds: 200), | ||
| padding: const EdgeInsets.symmetric( | ||
| horizontal: 14, | ||
| vertical: 8, | ||
| ), | ||
| decoration: BoxDecoration( | ||
| color: isSelected | ||
| ? tag.color | ||
| : tag.color.withValues(alpha: 0.1), | ||
| borderRadius: BorderRadius.circular(20), | ||
| ), | ||
| child: Row( | ||
| mainAxisSize: MainAxisSize.min, | ||
| children: [ | ||
| if (isSelected) ...[ | ||
| const Icon(Icons.check, color: Colors.white, size: 14), | ||
| const SizedBox(width: 4), | ||
| ], | ||
| Text( | ||
| tag.name, | ||
| style: TextStyle( | ||
| fontSize: 13, | ||
| fontWeight: FontWeight.w500, | ||
| color: isSelected ? Colors.white : tag.color, | ||
| ), | ||
| ), | ||
| ], | ||
| ), | ||
| ), | ||
| ); | ||
| }).toList(), |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's locate and examine the tag_selector.dart file
find . -name "tag_selector.dart" -type fRepository: tqha1011/TaskManagement
Length of output: 122
🏁 Script executed:
# Also search for priority_selector to understand the referenced comparison
find . -name "*priority*selector*" -type fRepository: tqha1011/TaskManagement
Length of output: 127
🏁 Script executed:
# Read the tag_selector.dart file to see the full implementation
cat -n ./src/lib/features/tasks/view/widgets/tag_selector.dartRepository: tqha1011/TaskManagement
Length of output: 2480
🏁 Script executed:
# Read the priority_selector.dart file to compare
cat -n ./src/lib/features/tasks/view/widgets/priority_selector.dartRepository: tqha1011/TaskManagement
Length of output: 2892
🏁 Script executed:
# Check if there are any other uses of FilterChip in the codebase
rg "FilterChip" --type dartRepository: tqha1011/TaskManagement
Length of output: 441
🏁 Script executed:
# Let's also check what Flutter version or material design widgets are being used
find . -name "pubspec.yaml" -type f | head -5Repository: tqha1011/TaskManagement
Length of output: 85
🏁 Script executed:
# Check pubspec.yaml to see Flutter version and dependencies
cat -n ./src/pubspec.yamlRepository: tqha1011/TaskManagement
Length of output: 4722
🏁 Script executed:
# Examine the home_screen.dart to see how _FilterChip is implemented
cat -n ./src/lib/features/tasks/view/screens/home_screen.dart | grep -A 50 "class _FilterChip"Repository: tqha1011/TaskManagement
Length of output: 1294
🏁 Script executed:
# Let's search for any imports or usage of Flutter's Material FilterChip (not custom)
rg "from 'package:flutter/material.dart'" -A 5 ./src/lib/features/tasks/view/widgets/tag_selector.dartRepository: tqha1011/TaskManagement
Length of output: 49
🏁 Script executed:
# Search for any Semantics or Focus handling in the codebase
rg "Semantics|Focus|FocusableActionDetector" --type dart | head -20Repository: tqha1011/TaskManagement
Length of output: 2117
🌐 Web query:
Flutter Material FilterChip multi-select accessibility focus semantics
💡 Result:
- Use
FilterChipfor true multi-select: it’s designed for selecting multiple filters; drive it withselected:and update state inonSelected:. [1] - Rely on built-in “button” semantics (don’t re-wrap unless you must): interactive Material chips (
FilterChipincluded) are now exposed to assistive tech as buttons automatically, improving screen-reader behavior versus older Flutter versions. [2] - Ensure the chip’s label is meaningful to screen readers: prefer a plain
Text('…')label; if you use non-textual/complex labels, add an explicitSemantics(label: ...)(or otherwise ensure an accessible label). (The chip being a button doesn’t guarantee a good label.) [2] - Make selection state discoverable: selection is typically conveyed via the semantics “selected” flag; if you build custom semantics around chips, ensure you expose a selected state (Flutter’s semantics model uses an
isSelectedflag). [3] - Keyboard focus & traversal (desktop/web/TV): chips participate in Flutter’s focus system; if you need predictable tab/arrow traversal across many chips, use
FocusTraversalGroup+ an ordering policy (or explicitFocusOrder) and per-chipFocusNodes. [4]
Sources: Flutter FilterChip API docs [1], Flutter breaking-change note on chip button semantics [2], Flutter semantics isSelected flag docs [3], Flutter focus system docs [4].
Replace GestureDetector with Flutter Material FilterChip for proper accessibility.
Tags use a multi-select pattern but wrap GestureDetector around custom widgets, which lacks semantic button role, focus handling, and selection state semantics. FilterChip automatically exposes selection state to screen readers and participates in the focus system, making it the correct choice here.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/lib/features/tasks/view/widgets/tag_selector.dart` around lines 17 - 55,
Replace the custom GestureDetector + AnimatedContainer tag widgets with
Flutter's FilterChip to restore proper accessibility and focus/selection
semantics: in the Wrap over viewModel.availableTags (where you currently call
viewModel.isTagSelected(tag) and viewModel.toggleTag(tag)), render a FilterChip
per tag with selected set from viewModel.isTagSelected(tag), onSelected calling
viewModel.toggleTag(tag), label using Text(tag.name) and styling via
selectedColor (tag.color), backgroundColor (tag.color.withOpacity(0.1)),
labelStyle (use white when selected, tag.color when not), padding and shape
(BorderRadius.circular(20)) to match current visuals, and optionally provide a
selectedIcon (Icons.check) to mimic the existing check display.
* Feature/user profile (#30) * feat(UserProfile): build screen UserProfile # Conflicts: # src/lib/features/main/view/screens/main_screen.dart * feat: switch dark/light theme * fix: black color theme * fix: black theme in statistics screen * feat: add dark theme to auth screen * feat: apply dark theme for bottom navigation bar * feat(priority task):Implement priority and tag selection in task creation version 1 (#31) * feat(task): implement priority and tag selection features in task creation * Update README.md * Update README.md * Update README.md --------- Co-authored-by: Tran Quang Ha <[email protected]> * Update README.md (#32) * feat: Priority selector and tag system verson2 (#33) * feat(task): implement priority and tag selection features in task creation * feat(tags): enhance tag management with custom tag creation and selection * Update README.md * Update README.md * fix: error screen in main.dart (#34) * Enhance authentication UI and implement Focus feature set (#35) * feat(core): add auth layout template, custom textfield and colors * feat(auth): implement viewmodels for auth flow (MVVM) * feat(auth): build complete auth UI screens (Login, Register, OTP, Passwords) * chore(main): set LoginView as initial route * refactor(auth) : delete .gitkeep * chore: update dependencies and pubspec.lock * refactor(auth): optimize registration logic, timezone handling, and form validation * feat(auth): update UI for login, registration, and forgot password screens * feat(tasks): update task management UI and statistics screen * chore: update main entry point and fix widget tests * chore: ignore devtools_options.yaml * chore: ignore devtools_options.yaml * style(login) : rewrite title for login view * feat(auth): configure android deep link for supabase oauth * refactor(ui): add social login callbacks to auth layout template * feat(auth): update oauth methods with redirect url and signout * feat(auth): implement AuthGate using StreamBuilder for session tracking * feat(viewmodel): add oauth logic and improve provider lifecycle * refactor(ui): migrate LoginView to Provider pattern * chore(main): set AuthGate as initial route and setup provider * feat: implement full Focus feature set - Added Pomodoro timer with Start/Reset/Skip logic. - Integrated local Quick Notes with Pin/Delete functionality. - Supported image attachments in notes using image_picker. - Added Focus settings: time duration, vibration, and ringtones. * fix (auth) : dispose TextEditingControllers to prevent memory leaks * refactor (alarm ) : create off alarm button when time out * fix: apply CodeRabbit auto-fixes Fixed 3 file(s) based on 4 unresolved review comments. Co-authored-by: CodeRabbit <[email protected]> * fix(timer): prevent division by zero in progress calculation and sanitize negative settings input * fix(timer): prevent division by zero in progress calculation and sanitize negative settings input * fix(auth): unblock new-user login and add settings logout * refactor(LoginScreen) : compact all items to fit in screen to help users interface easily --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: CodeRabbit <[email protected]> * build(deps)(deps): bump shared_preferences from 2.5.4 to 2.5.5 in /src (#36) Bumps [shared_preferences](https://github.com/flutter/packages/tree/main/packages/shared_preferences) from 2.5.4 to 2.5.5. - [Commits](https://github.com/flutter/packages/commits/shared_preferences-v2.5.5/packages/shared_preferences) --- updated-dependencies: - dependency-name: shared_preferences dependency-version: 2.5.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Feature/user profile (#37) * feat(UserProfile): build screen UserProfile # Conflicts: # src/lib/features/main/view/screens/main_screen.dart * feat: switch dark/light theme * fix: black color theme * fix: black theme in statistics screen * feat: add dark theme to auth screen * feat: apply dark theme for bottom navigation bar * feat(RPC): update RPC to get data for heatmap * feat(RPC): update new RPC to get data for heatmap * feat: integrate chatbot assistant * feat(chatbot): integrate create task, answer question for chatbot * feat: remove mock data and get data tags and categories from supabase * feat: integrate chatbot's ability to create task --------- Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Nguyễn Anh Kiệt <[email protected]> Co-authored-by: Nguyễn Lê Hoàng Hảo <[email protected]> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: CodeRabbit <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* feat: add create task screen and fix home screen provider errors * Feature/user profile (#30) * feat(UserProfile): build screen UserProfile # Conflicts: # src/lib/features/main/view/screens/main_screen.dart * feat: switch dark/light theme * fix: black color theme * fix: black theme in statistics screen * feat: add dark theme to auth screen * feat: apply dark theme for bottom navigation bar * feat(priority task):Implement priority and tag selection in task creation version 1 (#31) * feat(task): implement priority and tag selection features in task creation * Update README.md * Update README.md * Update README.md --------- Co-authored-by: Tran Quang Ha <[email protected]> * Remove comment about main UI in home_screen.dart Removed commented section about main UI. * Update README.md (#32) * feat: Priority selector and tag system verson2 (#33) * feat(task): implement priority and tag selection features in task creation * feat(tags): enhance tag management with custom tag creation and selection * Update README.md * Update README.md * fix: error screen in main.dart (#34) * Enhance authentication UI and implement Focus feature set (#35) * feat(core): add auth layout template, custom textfield and colors * feat(auth): implement viewmodels for auth flow (MVVM) * feat(auth): build complete auth UI screens (Login, Register, OTP, Passwords) * chore(main): set LoginView as initial route * refactor(auth) : delete .gitkeep * chore: update dependencies and pubspec.lock * refactor(auth): optimize registration logic, timezone handling, and form validation * feat(auth): update UI for login, registration, and forgot password screens * feat(tasks): update task management UI and statistics screen * chore: update main entry point and fix widget tests * chore: ignore devtools_options.yaml * chore: ignore devtools_options.yaml * style(login) : rewrite title for login view * feat(auth): configure android deep link for supabase oauth * refactor(ui): add social login callbacks to auth layout template * feat(auth): update oauth methods with redirect url and signout * feat(auth): implement AuthGate using StreamBuilder for session tracking * feat(viewmodel): add oauth logic and improve provider lifecycle * refactor(ui): migrate LoginView to Provider pattern * chore(main): set AuthGate as initial route and setup provider * feat: implement full Focus feature set - Added Pomodoro timer with Start/Reset/Skip logic. - Integrated local Quick Notes with Pin/Delete functionality. - Supported image attachments in notes using image_picker. - Added Focus settings: time duration, vibration, and ringtones. * fix (auth) : dispose TextEditingControllers to prevent memory leaks * refactor (alarm ) : create off alarm button when time out * fix: apply CodeRabbit auto-fixes Fixed 3 file(s) based on 4 unresolved review comments. Co-authored-by: CodeRabbit <[email protected]> * fix(timer): prevent division by zero in progress calculation and sanitize negative settings input * fix(timer): prevent division by zero in progress calculation and sanitize negative settings input * fix(auth): unblock new-user login and add settings logout * refactor(LoginScreen) : compact all items to fit in screen to help users interface easily --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: CodeRabbit <[email protected]> * build(deps)(deps): bump shared_preferences from 2.5.4 to 2.5.5 in /src (#36) Bumps [shared_preferences](https://github.com/flutter/packages/tree/main/packages/shared_preferences) from 2.5.4 to 2.5.5. - [Commits](https://github.com/flutter/packages/commits/shared_preferences-v2.5.5/packages/shared_preferences) --- updated-dependencies: - dependency-name: shared_preferences dependency-version: 2.5.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Feature/user profile (#37) * feat(UserProfile): build screen UserProfile # Conflicts: # src/lib/features/main/view/screens/main_screen.dart * feat: switch dark/light theme * fix: black color theme * fix: black theme in statistics screen * feat: add dark theme to auth screen * feat: apply dark theme for bottom navigation bar * feat(RPC): update RPC to get data for heatmap * feat(RPC): update new RPC to get data for heatmap * feat: integrate chatbot assistant * feat(chatbot): integrate create task, answer question for chatbot * feat: remove mock data and get data tags and categories from supabase * fixed codes, added save delete and create tasks and notes * Delete .vs/TaskManagement.slnx/v18/.wsuo * Delete .vs directory * Delete .vscode directory * Delete src/.gitignore * Delete src/lib/features/auth/viewmodels/task_provider.dart * Delete src/web_entrypoint.dart --------- Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Tran Quang Ha <[email protected]> Co-authored-by: Nguyễn Anh Kiệt <[email protected]> Co-authored-by: Nguyễn Lê Hoàng Hảo <[email protected]> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: CodeRabbit <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Thử nghiệm
Summary by CodeRabbit
New Features
Documentation